from django.shortcuts import render
from rest_framework import viewsets
from rest_framework.permissions import IsAuthenticated, IsAuthenticatedOrReadOnly
from django.db import transaction
from rest_framework.exceptions import ParseError
from rest_framework import status
from rest_framework.decorators import action
from rest_framework.response import Response
from .models import *
from .serializers import *
from . import flows
from .filters import *
from apps.cicd.handles.handles import get_yaml_template, get_workorder_kube_and_namespace, get_repotags, workorder_flow_function, get_workorder_pods, get_deployment_replicas, get_repotags_by_service, demandorder_auto_do, workorder_auto_do, get_deployment_resources
from .enums import UpdateChoices
from apps.resource.views import BusinessViewSet, ProjectViewSet, ServiceViewSet
import logging
import re

logger = logging.getLogger(__name__)
# Create your views here.




class CapacityViewSet(viewsets.ModelViewSet):
    queryset = Capacity.objects.all()
    serializer_class = CapacitySerializer
    permission_classes = [IsAuthenticated]
    filter_class = CapacityFilter

class YAMLTemplateViewSet(viewsets.ModelViewSet):
    queryset = YAMLTemplate.objects.all()
    serializer_class = YAMLTemplateSerializer
    permission_classes = [IsAuthenticated]
    filter_class = YAMLTemplateFilter

class BusinessEnvSettingViewSet(BusinessViewSet):
    serializer_class = BusinessEnvSettingSerializer


class ProjectEnvSettingViewSet(ProjectViewSet):
    serializer_class = ProjectEnvSettingSerializer


class ServiceEnvSettingViewSet(ServiceViewSet):
    serializer_class = ServiceEnvSettingSerializer




class LobEnvSettingViewSet(viewsets.ModelViewSet):
    queryset = LobEnvSetting.objects.all()
    serializer_class = LobEnvSettingSerializer
    permission_classes = [IsAuthenticated]
    filter_class = LobEnvSettingFilter
    # def get_queryset(self):
    #     queryset = super().get_queryset()
    #     print(self.request)
    #     if self.request.method == 'get':
    #         data = self.request.GET
    #         if not data.get('project_id', None):
    #             queryset = queryset.filter(project_id__isnull=True)
    #         if not data.get('service_id', None):
    #             queryset = queryset.filter(service_id__isnull=True)
    #     return queryset

    @action(methods=['get'], detail=False)
    def viewyaml(self, request, *args, **kwargs):
        data = request.GET
        service_id = request.GET.get('service_id')
        project_id = request.GET.get('service_id')
        business_id = request.GET.get('business_id')
        env_id = request.GET.get('env_id')
        object = LobEnvSetting.objects.filter(service_id=service_id).filter( env_id=env_id).last()
        if not object:
            object = LobEnvSetting.objects.filter(project_id=project_id, env_id=env_id, service_id__isnull=True).last()
        if not object:
            object = LobEnvSetting.objects.filter(business_id=business_id,  env_id=env_id, project_id__isnull=True, service_id__isnull=True).last()
        if not object:
            return Response({})
        else:
            service_name = get_service_name(service_id)
            return Response({'service_name': service_name,
                             })



class LobYamlSettingViewSet(viewsets.ModelViewSet):
    queryset = LobYamlSetting.objects.all()
    serializer_class = LobYamlSettingSerializer
    permission_classes = [IsAuthenticated]


class UpdateTypeViewSet(viewsets.ViewSet):
    def list(self, request, *args, **kwargs):
        data = []
        for k,v in UpdateChoices:
            data.append({'key': k, 'value': v})
        return Response(data)


class WorkOrderViewSet(viewsets.ModelViewSet):
    queryset = WorkOrder.objects.filter(delete=0).order_by('-created')
    serializer_class = WorkOrderSerializer
    permission_classes = [IsAuthenticated]
    filter_class = WorkOrderFilter
    def perform_create(self, serializer):
        serializer.save(creator=self.request.user.name)
    def list(self, request, *args, **kwargs):
        queryset = self.filter_queryset(self.get_queryset())
        order_type = request.GET.get('order_type', None)
        if order_type:
            queryset = queryset.filter(order_type=order_type)

        page = self.paginate_queryset(queryset)
        if page is not None:
            serializer = self.get_serializer(page, many=True)
            return self.get_paginated_response(serializer.data)

        serializer = self.get_serializer(queryset, many=True)
        return Response(serializer.data)

   
    @action(methods=['GET'], detail=True)
    def steps(self, request, pk):
        obj = self.get_object()
        # steps = obj.get_steps()
        # flow_function = getattr(flows, obj.get_flow_obj().function)(workorder=obj, username=request.user.username)
        flow_function = workorder_flow_function(workorder=obj, username=request.user.username)
        datas = getattr(flow_function, 'full_steps')()
        if obj.status == 'wait':
            active = len(obj.steps.all())-1
        else:
            active = len(obj.steps.all())
        last_step = obj.steps.last()
        current_opuser = last_step.opuser
        current_step = last_step.step.function
        return Response({'code': 20000, 'data': datas, 'active': active, 'status': obj.status, 'current_opuser': current_opuser, 'current_step': current_step})

    def create(self, request, *args, **kwargs):
        serializer = self.get_serializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        self.perform_create(serializer)
        headers = self.get_success_headers(serializer.data)
        obj = WorkOrder.objects.get(id=serializer.data['id'])
        # flow_function = getattr(flows, obj.get_flow_obj().function)(workorder=obj, username=request.user.username)
        # flow_function = getattr(flows, obj.get_flow_obj().function)(workorder=obj, username='chenyongbing')
        flow_function = workorder_flow_function(workorder=obj, username=request.user.username)
        getattr(flow_function, 'init')()
        return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers)

    @action(methods=['GET'], detail=True)
    def pods(self, request, pk):
        object = self.get_object()
        # kube = get_workorder_kube_and_namespace(object)
        data = get_workorder_pods(object)
        return Response(data)

    @action(methods=['GET'], detail=True)
    def info(self, request, pk):
        object = self.get_object()
        service = object.service
        data = {
            'service_name': service.name,
            'business_name': service.business.name,
            'order_type': object.order_type,
            'order_type_name': object.order_type_name,
            'version': object.version,
            'env_name': object.env.name,
            'replicas': object.replicas,
            'capacity_name': object.capacity.name if object.capacity else None
        }
        return Response({'code': 20000, 'data': data})

    @action(methods=['GET'], detail=False)
    def replicas(self, request):
        service_id = request.GET.get('service')
        env_id = request.GET.get('env')
       
        
        replicas = get_deployment_replicas(service_id, env_id)
        return Response({'code': 20000, 'replicas': replicas})

    @action(methods=['get'], detail=False)
    def resources(self, request):
        service_id = request.GET.get('service')
        env_id = request.GET.get('env')

        data = get_deployment_resources(service_id, env_id)
        return Response({'code': 20000, 'data': data})

    @action(methods=['GET'], detail=False)
    def repotags(self, request, *args, **kwargs):
        service_id = request.GET.get('service')
        env_id = request.GET.get('env')

        data = get_repotags_by_service(service_id, env_id)
        return Response({'code': 20000, 'data': data})



    @action(methods=['GET', 'POST'], detail=True)
    def do(self, request, pk):
        self.serializer_class = WorkOrderRunSerializer
        if request.method == 'GET':
            return Response('')

        step_function = request.data.get('step')
        action = request.data.get('action')
        obj = self.get_object()
        if re.search('auto', step_function):
            ret = workorder_auto_do(obj, step_function, request.user.username)
            return Response({'code': 20000, 'status': ret})
        # flow_function = getattr(flows, obj.get_flow_obj().function)(workorder=obj, username=request.user.username)
        flow_function = workorder_flow_function(workorder=obj, username=request.user.username)
        chk = getattr(flow_function, 'is_step_valid')(step_function, action)
        if not chk:
            return Response({'ret': 'step or action is invalid'})
        ret = getattr(flow_function, 'do')(step_function=obj.steps.last().step.function, action=action)
        return Response(ret)




    @action(methods=[ 'GET','POST'], detail=True)
    def next(self, request, pk):
        self.serializer_class = WorkOrderRunSerializer
        if request.method=='GET':
            return Response('')

        step_id = request.data.get('step')
        action = request.data.get('action')
        if action == 'retry':
            pass
        else:
            obj = self.get_object()
            info = obj.get_next_step(step_id, action)
            if action == 'no':
                status = 'fail'
            else:
                status = 'finish'

            # flow_function = getattr(flows,obj.get_flow_obj().function)(workorder=obj, username=request.user.username)
            flow_function = workorder_flow_function(workorder=obj, username=request.user.username)
            current_step_function = obj.steps.last().step_function
            next_step_function, next_step_env = obj.get_next_step_function()
            getattr(flow_function, current_step_function)(status=status)
            if next_step_function==None:
                obj.status = status
                obj.save()

            else:
                getattr(flow_function, next_step_function)(status='wait')
            # with transaction.atomic():
            #     cwos = obj.steps.last()
            #     cwos.status = status
            #     cwos.opuser = request.user.username
            #     cwos.save()
            #     next_step = info['next_step']
            #     step_function = next_step.stage.function + '__' + next_step.function
            #     wos = WorkOrderStep(workorder=obj, stage_name=next_step.stage.name, step_name=next_step.name, step_function=step_function, step_env=info['next_step_env'], status='wait', result='')
            #     wos.save()
            return Response('ok')

        
    

    # @action(methods=['get'], detail=True)
    # def info(self, request, pk):
    #     steps = []
    #
    #     workorder = self.get_object()
    #     envs = workorder.envs.split(',')
    #     flow = Flow.objects.get(id=1)
    #     current_step = None
    #     current_stage = None
    #     for workorderstep in workorder.steps.all():
    #         steps.append({
    #             'step_name': workorderstep.step_name,
    #             'step': workorderstep.step.function,
    #             'step_env': workorderstep.step_env,
    #             'status': workorderstep.status
    #         })
    #         current_step = workorderstep.step
    #         current_stage = workorderstep.stage
    #         current_step_env = workorderstep.step_env
    #     if workorder.status == 'success' or workorder.status == 'finish':
    #         return Response({'steps': steps})
    #     stages = [stage.stage.function for stage in flow.stages.order_by('order')]
    #     for flowstage in flow.stages.order_by('order'):
    #         if stages.index(flowstage.stage.function) < stages.index(current_stage):continue
    #         if flowstage.stage.function == current_stage:
    #             if current_step:
    #                 while 1:
    #                     current_step = current_step.stagestep.first().yes_step
    #                     if current_step:
    #                         steps.append({
    #                             'step_name': current_step.yes_step.name,
    #                             'step': current_step.yes_step.function,
    #                             'step_env': current_step_env,
    #                         })
    #                     else:
    #                         break
    #         if flowstage.stage.env_loop:
    #             for env in envs:
    #                 current_step_env = env
    #                 current_step = flowstage.steps.first()
    #                 if current_step:
    #                     while 1:
    #                         current_step = current_step.stagestep.first().yes_step
    #                         if current_step:
    #                             steps.append({
    #                                 'step_name': current_step.yes_step.name,
    #                                 'step': current_step.yes_step.function,
    #                                 'step_env': current_step_env,
    #                             })
    #                         else:
    #                             break
    #
    #
    #
    #     return Response({'steps': steps})
    #
class FlowViewSet(viewsets.ModelViewSet):
    queryset = Flow.objects.all()
    serializer_class = FlowSerializer
    permission_classes = [IsAuthenticated]

    # @action(methods=['get'], detail=True)
    # def stages(self, request, pk):
    #     obj = self.get_object()
    #     stages = obj.get_stages()
    #     return Response(stages)

    # @action(methods=['get'], detail=True)
    # def steps(self, request, pk):
    #     obj = self.get_object()
    #     steps = obj.get_steps()
    #     return Response(steps)

# class StageViewSet(viewsets.ModelViewSet):
#     queryset = Stage.objects.all()
#     serializer_class = StageSerializer
#     permission_classes = [IsAuthenticated]
#
#     @action(methods=['get'], detail=True)
#     def steps(self, request, pk):
#         obj = self.get_object()
#         steps = obj.get_steps()
#         return Response(steps)

class StepViewSet(viewsets.ModelViewSet):
    queryset = Step.objects.all()
    serializer_class = StepSerializer
    permission_classes = [IsAuthenticated]

# class FlowStageViewSet(viewsets.ModelViewSet):
#     queryset = FlowStage.objects.all()
#     serializer_class = FlowStageSerializer
#
# class StageStepViewSet(viewsets.ModelViewSet):
#     queryset = StageStep.objects.all()
#     serializer_class = StageStepSerializer

class WorkOrderStepViewSet(viewsets.ModelViewSet):
    queryset = WorkOrderStep.objects.all()
    serializer_class = WorkOrderStepSerializer
    permission_classes = [IsAuthenticated]



class DemandOrderViewSet(viewsets.ModelViewSet):
    queryset = DemandOrder.objects.all().order_by("-id")
    serializer_class = DemandOrderSerializer
    permission_classes = [IsAuthenticated]
    def perform_create(self, serializer):
        serializer.save(creator=self.request.user.name)
    def create(self, request, *args, **kwargs):
        serializer = self.get_serializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        business_id = serializer.initial_data.get('business_id')
        orders = self.queryset.filter(business_id=business_id, status='wait')
        if len(orders) !=0:
            ids = [str(order.id) for order in orders]
            # raise ParseError("存在{}个未完成的发布单[{}],请先完成后再发布".format(len(orders), ','.join(ids)))
            return Response({'code': 10000, 'message': '存在{}个未完成的工单，分别是{}'.format(len(orders), ','.join(ids))})
        self.perform_create(serializer)
        headers = self.get_success_headers(serializer.data)
        return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers)

    # def perform_create(self, serializer):
    #     with transaction.atomic():
    #         serializer.save()
    #         services = serializer.data.get('services', [])
    #         for service_id in services:
    #             wo = WorkOrder(service__id=service_id, parent__id=serializer.id,
    #                            order_type='update',update_type=serializer.update_type,
    #                            env=serializer.env, expected_time=serializer.expected_time,
    #                            )
    @action(methods=['POST'], detail=True)
    def recordorders(self, request, pk):
        '''录入工单'''
        services = request.data.get('services', [])
        src = request.data.get('src')
        obj = self.get_object()
        with transaction.atomic():
            errService = []
            next_step = None
            for service in services:
                service_id = service.get('id')
                service_name = service.get('name')
                version = service.get('version', '').strip()
                if not version:
                    errService.append(service_name)
                    continue

                if service_id:
                    serviceobj = Service.objects.get(business=obj.business, id=service_id)
                elif service_name:
                    serviceobj = Service.objects.filter(business=obj.business, code=service_name).first()
                else:
                    serviceobj = None
                if serviceobj == None:
                    errService.append(service_name)
                    continue
                oldworder = obj.orders.filter(service_id=serviceobj.id).last()
                if oldworder:
                    if src == 'tapd': continue
                    oldworder.delete = 1
                    oldworder.save()
                worder = WorkOrder(demand=obj, service_id=serviceobj.id, version=version,

                                   order_type=obj.order_type, update_type=obj.update_type,
                                   env_id=obj.env.id, expected_time=obj.expected_time,
                                   creator=obj.creator)

                worder.save()
                # flow_function = getattr(flows, worder.get_flow_obj().function)(workorder=worder, username=request.user.username)
                flow_function = workorder_flow_function(workorder=worder, username=request.user.username)
                ret = getattr(flow_function, 'init')()
                next_step_function = ret.get('next_step_function')
                next_step = worder.get_flow_obj().steps.filter(function=next_step_function).first()
            msg = "成功导入{}个，失败{}个".format(len(services) - len(errService), len(errService))
            if next_step != None:
                obj.status = 'wait'
                obj.step_id = next_step.id
                if src == 'tapd':
                    obj.comment = msg + '\n' +','.join(errService)
                obj.save()
            elif src == 'tapd':

                obj.comment = msg + '\n' + ','.join(errService)
                obj.save()
        ret = {'code': 20000, 'errService': errService, 'msg': msg}

        return Response(ret)





    @action(methods=['GET', 'POST'], detail=True)
    def do(self, request, pk):
        function = request.data.get('step')
        action = request.data.get('action')
        object = self.get_object()
        step = object.step
        if function != step.function:
            return Response({'code': 10000, 'msg': 'function {} is not allow.'.format(function)})
        if re.search('auto', function):
            ret = demandorder_auto_do(object, request.user.username)
            return Response({'code': 20000, 'msg': "异步执行完成", 'status': ret})
        try:
            with transaction.atomic():
                next_step_function = ''
                status = 'wait'
                for worder in object.orders.filter(delete=0):
                    cur_workorder_step = worder.steps.last()
                    if cur_workorder_step.step_id == step.id:
                        # flow_function = getattr(flows, worder.get_flow_obj().function)(workorder=worder, username=request.user.username)
                        flow_function = workorder_flow_function(workorder=worder, username=request.user.username)
                        ret = getattr(flow_function, 'do')(step.function, action=action)
                        next_step_function = ret.get('next_step_function')
                        status = ret.get('status')

                    else:
                        logging.warning('工单 {} 当前步骤{}与需求单{} 当前步骤{} 不一致, 跳过执行步骤'.format(
                            worder.id, cur_workorder_step.step.function, pk, step.function
                        ))
                if next_step_function != '':
                    next_step = worder.get_flow_obj().steps.filter(function=next_step_function).first()
                    object.step_id = next_step.id
                    object.status = status
                    object.save()

            return Response({'code': 20000, 'status': 'finish'})
        except Exception as error:
            logger.error(error)
            return Response({'code': 10000, 'msg': ''})

    @action(methods=['POST'], detail=True)
    def postrecordorders(self, request, pk):
        '''补录工单'''
        pass

    @action(methods=['POST'], detail=True)
    def autorecordorders(self, request, pk):
        '''自动录入'''
        pass

    @action(methods=['GET'], detail=True)
    def repotags(self, request, pk, *args, **kwargs):
        service_name = request.query_params.get('service_name')
        env = request.query_params.get('env')
        if not service_name:
            return Response({'code': 10000, 'msg': '缺少service_name'})
        obj = self.get_object()
        business_id = obj.business_id
        lobsettingobj = LobEnvSetting.objects.filter(business_id=business_id, project_id=None, service_id=None, env_id=obj.env_id).first()
        if not lobsettingobj:
            return Response({'code': 10000, 'msg': '缺少业务线环境配置'})
        data = get_repotags(repo=lobsettingobj.repo, repo_namespace_name=lobsettingobj.repo_namespace_src or lobsettingobj.repo_namespace, repo_name=service_name)

        return Response({'code': 20000, 'data': data})

    @action(methods=['GET'], detail=True)
    def latesttag(self, request, pk, *args, **kwargs):
        service_name = request.query_params.get('service_name')
        if not service_name:
            return Response({'code': 10000, 'msg': '缺少service_name'})
        obj = self.get_object()
        businessobj = obj.business
        lobsettingobj = LobEnvSetting.objects.filter(business_id=businessobj.id, project_id=None, service_id=None,
                                                     env_id=obj.env.id).first()
        if not lobsettingobj:
            return Response({'code': 10000, 'msg': '缺少业务线环境配置'})
        data = get_repotags(repo=lobsettingobj.repo, repo_namespace_name=lobsettingobj.repo_namespace_src or lobsettingobj.repo_namespace,
                            repo_name=service_name)
        if len(data) >0:
            imagetag = data[0].get('Tag', '')
        else:
            imagetag = ''
        return Response({'code': 20000, 'imagetag': imagetag})

    @action(methods=['GET'], detail=True)
    def steps(self, request, pk):
        obj = self.get_object()
        # steps = obj.get_steps()
        workorder = None
        olen = 100
        orders = obj.orders.filter(delete=0, status='wait') or obj.orders.filter(delete=0)
        for worder in orders:
            orderlen = len(worder.steps.all())
            if orderlen < olen:
                workorder = worder
                olen = orderlen
        if not workorder:
            return Response({'code': 20000, 'data': []})
        if workorder.steps.last().step_id != obj.step.id:
            obj.step_id = workorder.steps.last().step.id
            obj.status = workorder.status
            obj.save()
        # flow_function = getattr(flows, workorder.get_flow_obj().function)(workorder=workorder, username=request.user.username)
        flow_function = workorder_flow_function(workorder=workorder, username=request.user.username)
        datas = getattr(flow_function, 'full_steps')()
        if workorder.status == 'wait':
            active = len(workorder.steps.all()) - 1
        else:
            active = len(workorder.steps.all())
        last_step = workorder.steps.last()
        current_opuser = last_step.opuser
        current_step = last_step.step.function
        return Response(
            {'code': 20000, 'data': datas, 'active': active, 'status': obj.status, 'current_opuser': current_opuser,
             'current_step': current_step})

